home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / vm / vmSeg.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-19  |  57.4 KB  |  2,059 lines

  1. /* vmSeg.c -
  2.  *
  3.  *    This file contains routines that manage the segment table.   It
  4.  *    has routines to allocate, free, expand, and copy segments.  The 
  5.  *    segment table structure and the lists that run through the segment
  6.  *    table are described in vmInt.h.
  7.  *
  8.  * Copyright (C) 1985 Regents of the University of California
  9.  * All rights reserved.
  10.  */
  11.  
  12. #ifndef lint
  13. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/vm/vmSeg.c,v 9.16 92/04/10 16:45:03 kupfer Exp $ SPRITE (Berkeley)";
  14. #endif not lint
  15.  
  16. #include <sprite.h>
  17. #include <vm.h>
  18. #include <vmInt.h>
  19. #include <lock.h>
  20. #include <sync.h>
  21. #include <sys.h>
  22. #include <list.h>
  23. #include <stdlib.h>
  24. #include <fs.h>
  25. #include <status.h>
  26. #include <string.h>
  27. #include <stdio.h>
  28. #include <bstring.h>
  29. #include <assert.h>
  30. #include <machparam.h>
  31.  
  32. Boolean    vm_NoStickySegments = FALSE;        /* TRUE if sticky segments
  33.                          * are disabled. */
  34. Vm_Segment        *vm_SysSegPtr;        /* The system segment. */
  35.  
  36. static    Vm_Segment      *segmentTable;        /* The table of segments. */
  37.  
  38. Vm_SharedSegTable    sharedSegTable;        /* Table of shared segs. */
  39.  
  40. /*
  41.  * Free, inactive and dead segment lists.
  42.  */
  43. static    List_Links      freeSegListHdr;    
  44. static    List_Links      inactiveSegListHdr;
  45. static    List_Links      deadSegListHdr;
  46. #define    freeSegList    (&freeSegListHdr)
  47. #define    inactiveSegList    (&inactiveSegListHdr)
  48. #define    deadSegList    (&deadSegListHdr)
  49.  
  50. /*
  51.  * Condition to wait on when waiting for a code segment to be set up.
  52.  */
  53. Sync_Condition    codeSegCondition;
  54.  
  55. extern    Vm_Segment  **Fs_RetSegPtr();
  56. static void DeleteSeg _ARGS_((register Vm_Segment *segPtr));
  57. static void CleanSegment _ARGS_((register Vm_Segment *segPtr));
  58. static     void        FillSegmentInfo _ARGS_((Vm_Segment *segPtr, 
  59.                        Vm_SegmentInfo *infoPtr));
  60. static ReturnStatus AddToSeg _ARGS_((register Vm_Segment *segPtr,
  61.     int firstPage, int lastPage, int newNumPages, VmSpace newSpace,
  62.     VmSpace *oldSpacePtr));
  63. void            Fsio_StreamCopy();
  64.  
  65. #ifdef sequent
  66. int    vmNumSegments = 512;
  67. #else /* sequent */
  68. int    vmNumSegments = 256;
  69. #endif /* sequent */
  70.  
  71.  
  72. /*
  73.  * ----------------------------------------------------------------------------
  74.  *
  75.  * VmSegTableAlloc --
  76.  *
  77.  *     Allocate the segment table.
  78.  *
  79.  * Results:
  80.  *     None.
  81.  *
  82.  * Side effects:
  83.  *     Segment table allocated.
  84.  *     
  85.  * ----------------------------------------------------------------------------
  86.  */
  87. void
  88. VmSegTableAlloc()
  89. {
  90.     if (vmMaxMachSegs > 0) {
  91.     if (vmMaxMachSegs < vmNumSegments) {
  92.         vmNumSegments = vmMaxMachSegs;
  93.     }
  94.     }
  95.  
  96.     segmentTable = 
  97.         (Vm_Segment *) Vm_BootAlloc(sizeof(Vm_Segment) * vmNumSegments);
  98.     bzero((Address)segmentTable, vmNumSegments * sizeof(Vm_Segment));
  99.  
  100.     vm_SysSegPtr = &(segmentTable[VM_SYSTEM_SEGMENT]);
  101. }
  102.  
  103.  
  104. /*
  105.  * ----------------------------------------------------------------------------
  106.  *
  107.  * VmSegTableInit --
  108.  *
  109.  *     Initialize the segment table.
  110.  *
  111.  * Results:
  112.  *     None.
  113.  *
  114.  * Side effects:
  115.  *     Segment table initialized plus all segment lists.
  116.  *     
  117.  * ----------------------------------------------------------------------------
  118.  */
  119. void
  120. VmSegTableInit()
  121. {
  122.     int        i;
  123.     Vm_Segment    *segPtr;
  124.  
  125.     /*
  126.      * Initialize the free, inactive and dead segment lists.
  127.      */
  128.     List_Init(freeSegList);
  129.     List_Init(inactiveSegList);
  130.     List_Init(deadSegList);
  131.  
  132.     List_Init((List_Links *)&sharedSegTable);
  133.  
  134.     /*
  135.      * Initialize the segment table.  The kernel gets the system segment and
  136.      * the rest of the segments go onto the segment free list.
  137.      */
  138.     vm_SysSegPtr->refCount = 1;
  139.     vm_SysSegPtr->type = VM_SYSTEM;
  140.     vm_SysSegPtr->offset = (unsigned int)mach_KernStart >> vmPageShift;
  141.     vm_SysSegPtr->flags = 0;
  142.     vm_SysSegPtr->numPages = vmFirstFreePage;
  143.     vm_SysSegPtr->resPages = vmFirstFreePage;
  144.     for (i = 0, segPtr = segmentTable; i < vmNumSegments; i++, segPtr++) {
  145.     segPtr->filePtr = (Fs_Stream *)NIL;
  146.     segPtr->swapFilePtr = (Fs_Stream *)NIL;
  147.     segPtr->segNum = i;
  148.     segPtr->cowInfoPtr = (VmCOWInfo *)NIL;
  149.     segPtr->procList = (List_Links *) &(segPtr->procListHdr);
  150.     List_Init(segPtr->procList);
  151.     if (i != VM_SYSTEM_SEGMENT) {
  152.         segPtr->ptPtr = (Vm_PTE *)NIL;
  153.         segPtr->machPtr = (VmMach_SegData *)NIL;
  154.         segPtr->flags = VM_SEG_FREE;
  155.         List_Insert((List_Links *) segPtr, LIST_ATREAR(freeSegList));
  156.     }
  157.     }
  158. }
  159.  
  160. static Vm_Segment *FindCode _ARGS_((Fs_Stream *filePtr, VmProcLink *procLinkPtr, Boolean *usedFilePtr));
  161.  
  162.  
  163. /*
  164.  * ----------------------------------------------------------------------------
  165.  *
  166.  * Vm_FindCode --
  167.  *
  168.  *         Search the segment table for a code segment that has a matching 
  169.  *    filePtr.  Call internal routine to do the work.
  170.  *
  171.  * Results:
  172.  *         A pointer to the matching segment if one is found, NIL if none found. 
  173.  *
  174.  * Side effects:
  175.  *         Memory allocated, *execInfoPtrPtr may be set to point to exec info, and
  176.  *    *userFilePtr is set to TRUE or FALSE depending on whether the filePtr
  177.  *    is used.  If the segment couldn't be found, the file is marked 
  178.  *    to show that we're in the process of setting a segment up.
  179.  *
  180.  * ----------------------------------------------------------------------------
  181.  */
  182. ENTRY Vm_Segment *
  183. Vm_FindCode(filePtr, procPtr, execInfoPtrPtr, usedFilePtr)
  184.     Fs_Stream        *filePtr;    /* Stream for the object file. */
  185.     Proc_ControlBlock    *procPtr;    /* Process for which segment is being
  186.                      * allocated. */
  187.     Vm_ExecInfo        **execInfoPtrPtr;/* Where to return relevant info from
  188.                      * the a.out header. */
  189.     Boolean        *usedFilePtr;    /* TRUE => Had to use the file pointer.
  190.                      * FALSE => didn't have to use it. */
  191. {
  192.     register    Vm_Segment    *segPtr;
  193.     register    VmProcLink    *procLinkPtr;
  194.  
  195.     procLinkPtr = (VmProcLink *) malloc(sizeof(VmProcLink));
  196.     procLinkPtr->procPtr = procPtr;
  197.     segPtr = FindCode(filePtr, procLinkPtr, usedFilePtr);
  198.     if (segPtr == (Vm_Segment *) NIL) {
  199.     free((Address) procLinkPtr);
  200.     } else {
  201.     *execInfoPtrPtr = &segPtr->execInfo;
  202.     }
  203.  
  204.     return(segPtr);
  205. }
  206.  
  207.  
  208. /*
  209.  * ----------------------------------------------------------------------------
  210.  *
  211.  * FindCode --
  212.  *
  213.  *         Search the segment table for a code segment that has a matching 
  214.  *    filePtr.  If one can be found, then increment the reference count
  215.  *    and return a pointer to the segment.  If one can't be found then
  216.  *    mark the file so that subsequent calls to this routine will wait
  217.  *    until this code segment is initialized.
  218.  *
  219.  * Results:
  220.  *         A pointer to the matching segment if one is found, NIL if none found. 
  221.  *
  222.  * Side effects:
  223.  *         If a matching segment is found its reference count is incremented.
  224.  *    *usedFilePtr is set to TRUE or FALSE depending on whether the filePtr
  225.  *    needs to be used for the code segment or not.
  226.  *
  227.  * ----------------------------------------------------------------------------
  228.  */
  229. ENTRY static Vm_Segment *
  230. FindCode(filePtr, procLinkPtr, usedFilePtr)
  231.     Fs_Stream        *filePtr;    /* The unique identifier for this file
  232.                        (if any) */
  233.     VmProcLink        *procLinkPtr;    /* Used to put calling process into 
  234.                      * list of processes using this
  235.                      * segment. */
  236.     Boolean        *usedFilePtr;    /* TRUE => Had to use the file pointer.
  237.                      * FALSE => didn't have to use it. */
  238. {
  239.     register    Vm_Segment    **segPtrPtr;
  240.     register    Vm_Segment    *segPtr;
  241.     ClientData            fileHandle;
  242.  
  243.     LOCK_MONITOR;
  244.  
  245.     *usedFilePtr = FALSE;
  246. again:
  247.     fileHandle = Fs_GetFileHandle(filePtr);
  248.     assert(((unsigned int) fileHandle & WORD_ALIGN_MASK) == 0);
  249.     segPtrPtr = Fs_GetSegPtr(fileHandle);
  250.     if (vm_NoStickySegments || *segPtrPtr == (Vm_Segment *) NIL) {
  251.     /*
  252.      * There is no segment associated with this file.  Set the value to
  253.      * 0 so that we will know that we are about to set up this 
  254.      * association.
  255.      * XXX - if vm_NoStickySegments is TRUE, then we don't check
  256.      * whether there is really a segment associated with the file, 
  257.      * so code segments will apparently never be shared.  Is this 
  258.      * really what we want?  Can it cause a code segment leak?
  259.      */
  260.     *segPtrPtr = (Vm_Segment *) 0;
  261.     segPtr = (Vm_Segment *) NIL;
  262.     } else if (*segPtrPtr == (Vm_Segment *) 0) {
  263.     /*
  264.      * Someone is already trying to allocate this segment.  Wait for
  265.      * them to finish.
  266.      */
  267.     (void)Sync_Wait(&codeSegCondition, FALSE);
  268.     goto again;
  269.     } else {
  270.     segPtr = *segPtrPtr;
  271.     if (segPtr->flags & VM_SEG_INACTIVE) {
  272.         if (segPtr->fileHandle != fileHandle) {
  273.         panic("FindCode: segFileData != fileHandle\n");
  274.         }
  275.         /*
  276.          * The segment is inactive, so delete it from the inactive
  277.          * list.
  278.          */
  279.         List_Remove((List_Links *) segPtr);
  280.         segPtr->flags &= ~VM_SEG_INACTIVE;
  281.         segPtr->filePtr = filePtr;
  282.         *usedFilePtr = TRUE;
  283.     }
  284.     (segPtr->refCount)++;
  285.     /*
  286.      * Put the process into list of processes sharing this segment.
  287.      */
  288.     List_Insert((List_Links *) procLinkPtr, 
  289.             LIST_ATFRONT(segPtr->procList));
  290.     }
  291.  
  292.     UNLOCK_MONITOR;
  293.  
  294.     return(segPtr);
  295. }
  296.  
  297.  
  298. /*
  299.  * ----------------------------------------------------------------------------
  300.  *
  301.  * Vm_InitCode --
  302.  *
  303.  *         Set the association between the file pointer and the segment.  Also
  304.  *    set the exec information info for the segment.  If the segment is
  305.  *    NIL then any processes waiting for the file handle are awakened and
  306.  *    state is cleaned up.
  307.  *
  308.  * Results:
  309.  *         None.
  310.  *
  311.  * Side effects:
  312.  *         Exec info filled in and file pointers segment pointer filled in.
  313.  *
  314.  * ----------------------------------------------------------------------------
  315.  */
  316. ENTRY void
  317. Vm_InitCode(filePtr, segPtr, execInfoPtr)
  318.     Fs_Stream        *filePtr;    /* File for code segment. */
  319.     register Vm_Segment    *segPtr;    /* Segment that is being initialized. */
  320.     Vm_ExecInfo        *execInfoPtr;    /* Information needed to exec this 
  321.                      * object file. */
  322. {
  323.     register    Vm_Segment    **segPtrPtr;
  324.     char            *fileNamePtr;
  325.     int                length;
  326.     ClientData            fileHandle;
  327.  
  328.     LOCK_MONITOR;
  329.  
  330.     fileHandle = Fs_GetFileHandle(filePtr);
  331.     assert(((unsigned int) fileHandle & WORD_ALIGN_MASK) == 0);
  332.     segPtrPtr = Fs_GetSegPtr(fileHandle);
  333.     if (*segPtrPtr != (Vm_Segment *) 0) {
  334.     printf("Warning: Vm_InitCode: Seg ptr = %x\n", *segPtrPtr);
  335.     }
  336.     *segPtrPtr = segPtr;
  337.     if (segPtr == (Vm_Segment *) NIL) {
  338.     /*
  339.      * The caller doesn't want to set up any association between the file
  340.      * and the segment.  In this case cleanup state, i.e., notify any 
  341.      * other processes that might be waiting for the caller (our 
  342.      * process) to finish the association.
  343.      * XXX - Notice that this is the only place where there is a 
  344.      * wakeup on codeSegCondition.  If the caller completes the 
  345.      * association and there are processes waiting, these 
  346.      * processes won't get notified until some other process kills 
  347.      * a partial association.
  348.      */
  349.     Sync_Broadcast(&codeSegCondition);
  350.     } else {
  351.     extern    char    *Fsutil_GetFileName();
  352.     
  353.     segPtr->execInfo = *execInfoPtr;
  354.     segPtr->fileHandle = Fs_GetFileHandle(filePtr);
  355.     fileNamePtr = Fsutil_GetFileName(filePtr);
  356.     if (fileNamePtr != (char *)NIL) {
  357.         length = strlen(fileNamePtr);
  358.         if (length >= VM_OBJ_FILE_NAME_LENGTH) {
  359.         length = VM_OBJ_FILE_NAME_LENGTH - 1;
  360.         }
  361.         (void)strncpy(segPtr->objFileName, fileNamePtr, length);
  362.         segPtr->objFileName[length] = '\0';
  363.     } else {
  364.         segPtr->objFileName[0] = '\0';
  365.     }
  366.     }
  367.  
  368.     UNLOCK_MONITOR;
  369. }
  370.  
  371.  
  372. /*
  373.  *----------------------------------------------------------------------
  374.  *
  375.  * Vm_FileChanged --
  376.  *
  377.  *    This routine is called by the file system when it detects that a
  378.  *    file has been opened for writing.  If the file corresponds to
  379.  *    an unused sticky code segment, the segment will be marked as
  380.  *    deleted.
  381.  *
  382.  * Results:
  383.  *    None.
  384.  *
  385.  * Side effects:
  386.  *    Segment entry may be marked as deleted and put onto the
  387.  *    dead segment list.
  388.  *
  389.  *----------------------------------------------------------------------
  390.  */
  391. ENTRY void
  392. Vm_FileChanged(segPtrPtr)
  393.     Vm_Segment        **segPtrPtr;
  394. {
  395.     register    Vm_Segment    *segPtr;
  396.  
  397.     LOCK_MONITOR;
  398.  
  399.     segPtr = *segPtrPtr;
  400.     if (segPtr != (Vm_Segment *) NIL) {
  401.     if (segPtr->refCount != 0) {
  402.         panic("Vm_FileChanged: In use code seg modified.\n");
  403.     }
  404.     List_Move((List_Links *) segPtr, LIST_ATREAR(deadSegList));
  405.     *segPtrPtr = (Vm_Segment *) NIL;
  406.     segPtr->fileHandle = (ClientData) NIL;
  407.     }
  408.  
  409.     UNLOCK_MONITOR;
  410. }
  411.  
  412. static void GetNewSegment _ARGS_((int type, Fs_Stream *filePtr, int fileAddr, int numPages, int offset, Proc_ControlBlock *procPtr, VmSpace *spacePtr, Vm_Segment **segPtrPtr, Boolean *deletePtr));
  413.  
  414.  
  415. /*
  416.  * ----------------------------------------------------------------------------
  417.  *
  418.  * Vm_SegmentNew --
  419.  *
  420.  *      Allocate a new segment from the segment table.
  421.  *
  422.  * Results:
  423.  *      A pointer to the new segment is returned if a free segment
  424.  *      is available.  If no free segments are available, then NIL is returned.
  425.  *
  426.  * Side effects:
  427.  *      Memory is allocated.
  428.  *
  429.  * ----------------------------------------------------------------------------
  430.  */
  431. Vm_Segment *
  432. Vm_SegmentNew(type, filePtr, fileAddr, numPages, offset, procPtr)
  433.     int            type;        /* The type of segment that this is */
  434.     Fs_Stream        *filePtr;    /* The unique identifier for this file
  435.                        (if any) */
  436.     int            fileAddr;    /* The address where the segments image
  437.                        begins in the object file. */
  438.     int            numPages;    /* Initial size of segment (in pages) */
  439.     int            offset;        /* At which page from the beginning of
  440.                        the VAS that this segment begins */
  441.     Proc_ControlBlock    *procPtr;    /* Process for which the segment is
  442.                        being allocated. */
  443.  
  444. {
  445.     Vm_Segment        *segPtr;
  446.     VmSpace        space;
  447.     Boolean        deleteSeg;
  448.  
  449.     space.procLinkPtr = (VmProcLink *) malloc(sizeof(VmProcLink));
  450.     if (type == VM_CODE) {
  451.     space.ptPtr = (Vm_PTE *) malloc(sizeof(Vm_PTE) * numPages);
  452.     space.ptSize = numPages;
  453.     } else {
  454.     space.ptSize = ((numPages - 1) / vmPageTableInc + 1) * vmPageTableInc;
  455.     space.ptPtr = (Vm_PTE *) malloc(sizeof(Vm_PTE) * space.ptSize);
  456.     }
  457.     segPtr = (Vm_Segment *)NIL;
  458.     GetNewSegment(type, filePtr, fileAddr, numPages, offset,
  459.           procPtr, &space, &segPtr, &deleteSeg);
  460.     if (segPtr != (Vm_Segment *)NIL) {
  461.     if (deleteSeg) {
  462.         /*
  463.          * We have to recycle a code segment before we can allocate a new
  464.          * segment.
  465.          */
  466.         DeleteSeg(segPtr);
  467.         GetNewSegment(type, filePtr, fileAddr, numPages, offset,
  468.               procPtr, &space, &segPtr, &deleteSeg);
  469.     }
  470.     VmMach_SegInit(segPtr);
  471.     } else {
  472.     free((Address)space.procLinkPtr);
  473.     free((Address)space.ptPtr);
  474.     }
  475.     return(segPtr);
  476. }
  477.  
  478.  
  479. /*
  480.  * ----------------------------------------------------------------------------
  481.  *
  482.  * GetNewSegment --
  483.  *
  484.  *         Allocate a new segment from the segment table and return a pointer
  485.  *    to it in *segPtrPtr.  If the new segment corresponds to a dead or
  486.  *    inactive code segment, then *deletePtr will be set to TRUE and the 
  487.  *    caller must cleanup the segment that we returned and call us again 
  488.  *    with *segPtrPtr pointing to the segment that we returned.
  489.  *
  490.  * Results:
  491.  *      None.
  492.  *
  493.  * Side effects:
  494.  *    *segPtrPtr is set to point to a segment in the segment table to
  495.  *    use for the new segment.  If no segments are available then *segPtrPtr
  496.  *    is set to NIL.
  497.  *
  498.  * ----------------------------------------------------------------------------
  499.  */
  500. ENTRY static void
  501. GetNewSegment(type, filePtr, fileAddr, numPages, offset, procPtr,
  502.           spacePtr, segPtrPtr, deletePtr)
  503.     int            type;        /* The type of segment that this is */
  504.     Fs_Stream        *filePtr;    /* Object file stream. */
  505.     int            fileAddr;    /* The address where the segments image
  506.                      * begins in the object file. */
  507.     int            numPages;    /* The number of pages that this segment
  508.                      * initially has. */
  509.     int            offset;        /* At which page from the beginning of
  510.                      * the VAS that this segment begins */
  511.     Proc_ControlBlock    *procPtr;    /* Process for which the segment is
  512.                      *  being allocated. */
  513.     VmSpace        *spacePtr;    /* Memory to be used for this segment.*/    Boolean        *deletePtr;    /* TRUE if have to delete a segment*/
  514.     Vm_Segment        **segPtrPtr;    /* IN/OUT parameter: On input if 
  515.                      * non-nil then this segment should
  516.                      * be used.  On output is the segment
  517.                      * to use. */
  518. {
  519.     register    Vm_Segment    *segPtr;
  520.     register    VmProcLink    *procLinkPtr;
  521.  
  522.     LOCK_MONITOR;
  523.  
  524.     if (*segPtrPtr == (Vm_Segment *)NIL) {
  525.     if (!List_IsEmpty(deadSegList)) {
  526.         /*
  527.          * If there is a dead code segment then use it so that we can free
  528.          * up things.
  529.          */
  530.         segPtr = (Vm_Segment *) List_First(deadSegList);
  531.         *deletePtr = TRUE;
  532.     } else if (!List_IsEmpty(freeSegList)) {
  533.         /*
  534.          * If there is a free segment then use it.
  535.          */
  536.         segPtr = (Vm_Segment *) List_First(freeSegList);
  537.         *deletePtr = FALSE;
  538.     } else if (!List_IsEmpty(inactiveSegList)) {
  539.         /*
  540.          * Inactive segment is available so use it.
  541.          */
  542.         segPtr = (Vm_Segment *) List_First(inactiveSegList);
  543.         *deletePtr = TRUE;
  544.     } else {
  545.         /*
  546.          * No segments are available so return a NIL pointer in *segPtrPtr. 
  547.          */
  548.         *segPtrPtr = (Vm_Segment *)NIL;
  549.         UNLOCK_MONITOR;
  550.         return;
  551.     }
  552.     List_Remove((List_Links *) segPtr);
  553.     *segPtrPtr = segPtr;
  554.     } else {
  555.     segPtr = *segPtrPtr;
  556.     *deletePtr = FALSE;
  557.     }
  558.  
  559.     if (!*deletePtr) {
  560.     /*
  561.      * Initialize the new segment.
  562.      */
  563.     segPtr->fileHandle = (ClientData) NIL;
  564.     segPtr->flags = 0;
  565.     segPtr->refCount = 1;
  566.     segPtr->filePtr = filePtr;
  567.     segPtr->fileAddr = fileAddr;
  568.     segPtr->numPages = numPages;
  569.     segPtr->numCORPages = 0;
  570.     segPtr->numCOWPages = 0;
  571.     segPtr->type = type;
  572.     segPtr->offset = offset;
  573.     segPtr->swapFileName = (char *) NIL;
  574.     segPtr->ptPtr = spacePtr->ptPtr;
  575.     segPtr->ptSize = spacePtr->ptSize;
  576.     bzero((Address)segPtr->ptPtr, segPtr->ptSize * sizeof(Vm_PTE));
  577.     /*
  578.      * If this is a stack segment, the page table grows backwards.  
  579.      * Therefore all of the extra page table that we allocated must be
  580.      * taken off of the offset where the stack was supposed to begin.
  581.      */
  582.     if (segPtr->type == VM_STACK) {
  583.         segPtr->offset = mach_LastUserStackPage - segPtr->ptSize + 1;
  584.     }
  585.     /*
  586.      * Put the process into the list of processes sharing this segment.
  587.      */
  588.     procLinkPtr = spacePtr->procLinkPtr;
  589.     procLinkPtr->procPtr = procPtr;
  590.     List_Insert((List_Links *) procLinkPtr, LIST_ATFRONT(segPtr->procList));
  591.     }
  592.  
  593.     UNLOCK_MONITOR;
  594. }
  595.  
  596.  
  597. /*
  598.  * ----------------------------------------------------------------------------
  599.  *
  600.  * VmSegmentDeleteInt --
  601.  *
  602.  *      This routine will decrement the reference count for the given segment
  603.  *    and return a status to the caller to tell them what action to 
  604.  *    take.
  605.  *
  606.  * Results:
  607.  *    VM_DELETE_SEG -        The segment should be deleted.
  608.  *    VM_CLOSE_OBJ_FILE -    Don't delete the segment, but close the file
  609.  *                containing the code for the segment.
  610.  *    VM_DELETE_NOTHING -    Don't do anything.
  611.  *
  612.  * Side effects:
  613.  *      The segment table for the given segment is modified, the list of 
  614.  *    processes sharing this segment is modified and the inactive list
  615.  *    may be modified.  *objStreamPtrPtr is set to point to the object
  616.  *    file to close if the status is VM_CLOSE_OBJ_FILE.  *procLinkPtrPtr
  617.  *    is set to point to the proc link info struct to free.
  618.  *
  619.  * ----------------------------------------------------------------------------
  620.  */
  621. ENTRY VmDeleteStatus
  622. VmSegmentDeleteInt(segPtr, procPtr, procLinkPtrPtr, objStreamPtrPtr, migFlag)
  623.     register Vm_Segment     *segPtr;    /* Pointer to segment to 
  624.                            delete. */
  625.     register Proc_ControlBlock    *procPtr;    /* Process that was using
  626.                            this segment. */
  627.     VmProcLink            **procLinkPtrPtr;/* Pointer to proc link info
  628.                           * to free. */
  629.     Fs_Stream            **objStreamPtrPtr;/* Pointer to object file
  630.                            * stream to close. */
  631.     Boolean            migFlag;    /* TRUE if segment is being
  632.                            migrated. */
  633. {
  634.     VmProcLink        *procLinkPtr;
  635.  
  636.     LOCK_MONITOR;
  637.  
  638.     segPtr->refCount--;
  639.     
  640.     /*
  641.      * If the segment is not being migrated, then procPtr refers to a process
  642.      * in the list of processes sharing the segment.  Remove this process from
  643.      * the list of processes and make sure that the space is freed.
  644.      */
  645.     if (!migFlag) {
  646.     procLinkPtr = (VmProcLink *)
  647.             List_First((List_Links *) segPtr->procList);
  648.     while (procPtr != procLinkPtr->procPtr) {
  649.         if (List_IsAtEnd(segPtr->procList, (List_Links *) procLinkPtr)) {
  650.         dprintf("Warning: segment %x not on shared seg. list\n",
  651.             (int)segPtr);
  652.         dprintf("Want: %x (%x)\nHave:\n",(int)procLinkPtr->procPtr,
  653.             (int)procLinkPtr->procPtr->processID);
  654.         procLinkPtr = (VmProcLink *)
  655.             List_First((List_Links *) segPtr->procList);
  656.         do {
  657.             dprintf(" %x (%x)\n",(int)(procLinkPtr->procPtr),
  658.                 (int)(procLinkPtr->procPtr->processID));
  659.             procLinkPtr = (VmProcLink *) List_Next((List_Links *) procLinkPtr);
  660.         } while (!List_IsAtEnd(segPtr->procList, (List_Links *) procLinkPtr));
  661.  
  662.         panic("%s%s",
  663.                     "VmSegmentDeleteInt: Could not find segment on shared",
  664.             "segment list.\n");
  665.         }
  666.         procLinkPtr = (VmProcLink *) List_Next((List_Links *) procLinkPtr);
  667.     }
  668.     List_Remove((List_Links *) procLinkPtr);
  669.     *procLinkPtrPtr = procLinkPtr;
  670.     } else {
  671.     *procLinkPtrPtr = (VmProcLink *)NIL;
  672.     }
  673.  
  674.     if (segPtr->refCount > 0) {
  675.     /*
  676.      * The segment is still being used so there is nothing to do.
  677.      */
  678.     UNLOCK_MONITOR;
  679.     return(VM_DELETE_NOTHING);
  680.     }
  681.  
  682.     while (segPtr->ptUserCount > 0 ) {
  683.     dprintf("VmSegmentDeleteInt: ptUserCount = %d\n",segPtr->ptUserCount);
  684.     /*
  685.      * Wait until all users of the page tables of this segment are gone.
  686.      * The only remaining users of a deleted segment would be 
  687.      * prefetch processes.
  688.      */
  689.     (void)Sync_Wait(&segPtr->condition, FALSE);
  690.     dprintf("VmSegmentDeleteInt: done waiting\n");
  691.     }
  692.     if (segPtr->type == VM_SHARED) {
  693.     Vm_SharedSegTable *sharedSeg;
  694.     int found;
  695.     found = 0;
  696.     dprintf("Removing sharedSegTable entry\n");
  697.     LIST_FORALL((List_Links *)&sharedSegTable,(List_Links *)sharedSeg) {
  698.         if (sharedSeg->segPtr == segPtr) {
  699.         List_Remove((List_Links *)sharedSeg);
  700.         found = 1;
  701.         break;
  702.         }
  703.     }
  704.     if (!found) {
  705.         dprintf("Danger! shared segment not found on list!\n");
  706.     } else {
  707.         dprintf("VmSegmentDeleteInt: shared segment removed\n");
  708.     }
  709.     }
  710.     if (!vm_NoStickySegments && segPtr->type == VM_CODE &&
  711.         !(segPtr->flags & (VM_DEBUGGED_SEG | VM_SEG_IO_ERROR))) {
  712.     /* 
  713.      * Put onto the inactive list and tell our caller to close the
  714.      * object file.
  715.      */
  716.     segPtr->flags |= VM_SEG_INACTIVE;
  717.     *objStreamPtrPtr = segPtr->filePtr;
  718.     segPtr->filePtr = (Fs_Stream *) NIL;
  719.     List_Insert((List_Links *) segPtr, LIST_ATREAR(inactiveSegList));
  720.     UNLOCK_MONITOR;
  721.     return(VM_CLOSE_OBJ_FILE);
  722.     } else {
  723.     /*
  724.      * Otherwise tell our caller to delete us.
  725.      */
  726.     UNLOCK_MONITOR;
  727.     return(VM_DELETE_SEG);
  728.     }
  729. }
  730.  
  731.  
  732. /*
  733.  * ----------------------------------------------------------------------------
  734.  *
  735.  * VmPutOnFreeSegList --
  736.  *
  737.  *         Put the given segment onto the end of the segment free list.
  738.  *
  739.  * Results:
  740.  *     None.
  741.  *
  742.  * Side effects:
  743.  *     Segment put onto end of segment free list.
  744.  *
  745.  * ----------------------------------------------------------------------------
  746.  */
  747. ENTRY void
  748. VmPutOnFreeSegList(segPtr)
  749.     register    Vm_Segment    *segPtr;
  750. {
  751.     LOCK_MONITOR;
  752.  
  753.     segPtr->flags = VM_SEG_FREE;
  754.     List_Insert((List_Links *) segPtr, LIST_ATREAR(freeSegList));
  755.  
  756.     UNLOCK_MONITOR;
  757. }
  758.  
  759.  
  760. /*
  761.  * ----------------------------------------------------------------------------
  762.  *
  763.  * Vm_SegmentDelete --
  764.  *
  765.  *         This routine will delete the given segment by calling a monitored
  766.  *    routine to do most of the work.  Since the calls to the memory 
  767.  *    allocator must be done at non-monitor level, if the resources for
  768.  *    this segment must be released then the calls to the machine dependent
  769.  *    routine that uses the memory allocator are done here at non-monitored 
  770.  *    level.
  771.  *
  772.  * Results:
  773.  *     None.
  774.  *
  775.  * Side effects:
  776.  *     None.
  777.  *
  778.  * ----------------------------------------------------------------------------
  779.  */
  780. void
  781. Vm_SegmentDelete(segPtr, procPtr)
  782.     register    Vm_Segment    *segPtr;
  783.     Proc_ControlBlock        *procPtr;
  784. {
  785.     VmDeleteStatus    status;
  786.     VmProcLink        *procLinkPtr;
  787.     Fs_Stream        *objStreamPtr;
  788.  
  789.     status = VmSegmentDeleteInt(segPtr, procPtr, &procLinkPtr, &objStreamPtr,
  790.                 FALSE);
  791.     if (status == VM_DELETE_SEG) {
  792.     DeleteSeg(segPtr);
  793.     VmPutOnFreeSegList(segPtr);
  794.     } else if (status == VM_CLOSE_OBJ_FILE) {
  795.     (void)Fs_Close(objStreamPtr);
  796.     }
  797.  
  798.     free((Address)procLinkPtr);
  799. }
  800.  
  801.  
  802. /*
  803.  * ----------------------------------------------------------------------------
  804.  *
  805.  * DeleteSeg --
  806.  *
  807.  *    Actually delete a segment.  This includes freeing all memory 
  808.  *    resources for the segment and calling machine dependent cleanup.
  809.  *
  810.  * Results:
  811.  *         None.
  812.  *
  813.  * Side effects:
  814.  *         Allocated resources freed in the give segment and the pointers
  815.  *    in the segment are set to NIL.
  816.  *
  817.  * ----------------------------------------------------------------------------
  818.  */
  819. static void
  820. DeleteSeg(segPtr)
  821.     register    Vm_Segment    *segPtr;
  822. {
  823.     if (vm_CanCOW) {
  824.     VmCOWDeleteFromSeg(segPtr, -1, -1);
  825.     }
  826.     CleanSegment(segPtr);
  827.     VmMach_SegDelete(segPtr);
  828.  
  829.     free((Address)segPtr->ptPtr);
  830.     segPtr->ptPtr = (Vm_PTE *)NIL;
  831.     if (segPtr->filePtr != (Fs_Stream *)NIL) {
  832.     (void)Fs_Close(segPtr->filePtr);
  833.     segPtr->filePtr = (Fs_Stream *)NIL;
  834.     }
  835.     if (segPtr->flags & VM_SWAP_FILE_OPENED) {
  836.     VmSwapFileRemove(segPtr->swapFilePtr, segPtr->swapFileName);
  837.     segPtr->swapFilePtr = (Fs_Stream *)NIL;
  838.     segPtr->swapFileName = (char *)NIL;
  839.     }
  840. }
  841.  
  842.  
  843. /*
  844.  * ----------------------------------------------------------------------------
  845.  *
  846.  * CleanSegment --
  847.  *
  848.  *    Do monitor level state cleanup for a deleted segment.
  849.  *
  850.  * Results:
  851.  *         None.
  852.  *
  853.  * Side effects:
  854.  *         All pages allocated to the segment are freed.
  855.  *     
  856.  * ----------------------------------------------------------------------------
  857.  */
  858. ENTRY static void
  859. CleanSegment(segPtr)
  860.     register Vm_Segment *segPtr;    /* Pointer to the segment to be 
  861.                      * cleaned */
  862. {
  863.     register    Vm_PTE    *ptePtr;
  864.     register    int        i;
  865.     Vm_VirtAddr        virtAddr;
  866.     Vm_Segment        **segPtrPtr;
  867.  
  868.     LOCK_MONITOR;
  869.  
  870.     segPtr->flags |= VM_SEG_DEAD;
  871.  
  872.     virtAddr.segPtr = segPtr;
  873.     virtAddr.sharedPtr = (Vm_SegProcList *)NIL;
  874.     if (segPtr->type == VM_STACK) {
  875.     virtAddr.page = mach_LastUserStackPage - segPtr->numPages + 1;
  876.     } else {
  877.     virtAddr.page = segPtr->offset;
  878.     }
  879.     ptePtr = VmGetPTEPtr(segPtr, virtAddr.page);
  880.  
  881.     if (segPtr->fileHandle != (ClientData) NIL) {
  882.     /*
  883.      * This segment is associated with a file.  Find out which one and
  884.      * break the connection.
  885.      */
  886.     segPtrPtr = Fs_GetSegPtr(segPtr->fileHandle);
  887.     *segPtrPtr = (Vm_Segment *) NIL;
  888.     segPtr->fileHandle = (ClientData) NIL;
  889.     }
  890.  
  891.     /*
  892.      * Free all pages that this segment has in real memory.
  893.      */
  894.     for (i = segPtr->numPages; 
  895.          i > 0; 
  896.      i--, VmIncPTEPtr(ptePtr, 1), virtAddr.page++) {
  897.     if (*ptePtr & VM_PHYS_RES_BIT) {
  898.         VmMach_PageInvalidate(&virtAddr, Vm_GetPageFrame(*ptePtr),
  899.                   TRUE);
  900.         VmPageFreeInt(Vm_GetPageFrame(*ptePtr));
  901.     }
  902.     }
  903.  
  904.     segPtr->resPages = 0;
  905.  
  906.     UNLOCK_MONITOR;
  907. }
  908.  
  909. static Boolean StartDelete _ARGS_((Vm_Segment *segPtr, int firstPage, int *lastPagePtr));
  910. static ReturnStatus EndDelete _ARGS_((register Vm_Segment *segPtr, int firstPage, int lastPage));
  911.  
  912.  
  913. /*
  914.  *----------------------------------------------------------------------
  915.  *
  916.  * Vm_DeleteFromSeg --
  917.  *
  918.  *    Take the range of virtual page numbers for the given heap segment,
  919.  *    invalidate them, make them unaccessible and make the segment
  920.  *    smaller if necessary.
  921.  *    
  922.  * Results:
  923.  *    None.
  924.  *
  925.  * Side effects:
  926.  *    None.
  927.  *
  928.  *----------------------------------------------------------------------
  929.  */
  930. ReturnStatus
  931. Vm_DeleteFromSeg(segPtr, firstPage, lastPage)
  932.     Vm_Segment     *segPtr;    /* The segment whose pages are being
  933.                    invalidated. */
  934.     int        firstPage;    /* The first page to invalidate */
  935.     int        lastPage;    /* The second page to invalidate. */
  936. {
  937.     /*
  938.      * The deletion of virtual pages from the segment is done in two
  939.      * phases.  First the copy-on-write dependencies are cleaned up and
  940.      * then the rest of the pages are cleaned up.  This requires some
  941.      * synchronization.  The problem is that during and after cleaning up
  942.      * the copy-on-write dependencies, page faults and copy-on-write forks
  943.      * in the segment must be prevented since cleanup is done at non-monitor
  944.      * level.  This is done by using the VM_PT_EXCL_ACC flag.  When this flag 
  945.      * is set page faults and forks are blocked because they are unable
  946.      * to get access to the page tables until the exclusive access flag
  947.      * is cleared.  This flag is set by StartDelete and cleared by EndDelete. 
  948.      * The flag is looked at by VmVirtAddrParse (the routine that is called 
  949.      * before any page fault can occur on the segment) and by IncPTUserCount
  950.      * (the routine that is called when a segment is duplicated for a fork).
  951.      */
  952.     if (!StartDelete(segPtr, firstPage, &lastPage)) {
  953.     return(SUCCESS);
  954.     }
  955.     /*
  956.      * Rid the segment of all copy-on-write dependencies.
  957.      */
  958.     VmCOWDeleteFromSeg(segPtr, firstPage, lastPage);
  959.  
  960.     return(EndDelete(segPtr, firstPage, lastPage));
  961. }
  962.  
  963.  
  964. /*
  965.  *----------------------------------------------------------------------
  966.  *
  967.  * StartDelete --
  968.  *
  969.  *    Set things up to delete pages from a segment.  This involves grabbing
  970.  *    exclusive access to the page tables for the segment.
  971.  *
  972.  * Results:
  973.  *    FALSE if there is nothing to delete from this segment.
  974.  *
  975.  * Side effects:
  976.  *    Page table user count incremented and exclusive access grabbed on
  977.  *    the page tables.
  978.  *
  979.  *----------------------------------------------------------------------
  980.  */
  981. ENTRY static Boolean
  982. StartDelete(segPtr, firstPage, lastPagePtr)
  983.     Vm_Segment    *segPtr;
  984.     int        firstPage;
  985.     int        *lastPagePtr;
  986. {
  987.     Boolean    retVal;
  988.     int        lastSegPage;
  989.  
  990.     LOCK_MONITOR;
  991.  
  992.     while (segPtr->ptUserCount > 0) {
  993.     (void) Sync_Wait(&segPtr->condition, FALSE);
  994.     }
  995.  
  996.     /*
  997.      * If the beginning address falls past the end of the heap segment
  998.      * then there is nothing to do so return.  If the ending address 
  999.      * falls past the end of the heap segment then it must be rounded
  1000.      * down and the segment made smaller.
  1001.      */
  1002.     lastSegPage = segPtr->offset + segPtr->numPages - 1;
  1003.     if (firstPage <= lastSegPage) {
  1004.     if (*lastPagePtr >= lastSegPage) {
  1005.         *lastPagePtr = lastSegPage;
  1006.     }
  1007.     /*
  1008.      * Make sure that no one expands or shrinks the segment while 
  1009.      * we are expanding it.
  1010.      */
  1011.     segPtr->ptUserCount = 1;
  1012.     segPtr->flags |= VM_PT_EXCL_ACC;
  1013.     retVal = TRUE;
  1014.     } else {
  1015.     retVal = FALSE;
  1016.     }
  1017.     UNLOCK_MONITOR;
  1018.     return(retVal);
  1019. }
  1020.  
  1021.  
  1022. /*
  1023.  *----------------------------------------------------------------------
  1024.  *
  1025.  * EndDelete --
  1026.  *
  1027.  *    Clean up after a delete has finished.
  1028.  *
  1029.  * Results:
  1030.  *    None.
  1031.  *
  1032.  * Side effects:
  1033.  *    Page table user count decremented, exclusive access on the page tables
  1034.  *    is released and the segment size may be shrunk.
  1035.  *
  1036.  *----------------------------------------------------------------------
  1037.  */
  1038. ENTRY static ReturnStatus
  1039. EndDelete(segPtr, firstPage, lastPage)
  1040.     register    Vm_Segment    *segPtr;
  1041.     int                firstPage;
  1042.     int                lastPage;
  1043. {
  1044.     register    Vm_PTE    *ptePtr;
  1045.     Vm_VirtAddr        virtAddr;
  1046.     unsigned    int    pfNum;
  1047.     ReturnStatus    status = SUCCESS;
  1048.  
  1049.     LOCK_MONITOR;
  1050.  
  1051.     if (lastPage == segPtr->offset + segPtr->numPages - 1) {
  1052.     segPtr->numPages -= lastPage - firstPage + 1;
  1053.     }
  1054.  
  1055.     /*
  1056.      * Free up any resident pages.
  1057.      */
  1058.     virtAddr.segPtr = segPtr;
  1059.     virtAddr.sharedPtr = (Vm_SegProcList *)NIL;
  1060.     for (virtAddr.page = firstPage, ptePtr = VmGetPTEPtr(segPtr, firstPage);
  1061.      virtAddr.page <= lastPage;
  1062.      virtAddr.page++, VmIncPTEPtr(ptePtr, 1)) {
  1063.     if (*ptePtr & VM_PHYS_RES_BIT) {
  1064.         if (VmPagePinned(ptePtr)) {
  1065.         status = FAILURE;
  1066.         goto exit;
  1067.         }
  1068.         VmMach_PageInvalidate(&virtAddr, Vm_GetPageFrame(*ptePtr), FALSE);
  1069.         segPtr->resPages--;
  1070.         pfNum = Vm_GetPageFrame(*ptePtr);
  1071.         *ptePtr = 0;
  1072.         VmPageFreeInt(pfNum);
  1073.     }
  1074.     *ptePtr = 0;
  1075.     }
  1076.  
  1077. exit:
  1078.     /*
  1079.      * Release exclusive access.
  1080.      */
  1081.     segPtr->ptUserCount = 0;
  1082.     segPtr->flags &= ~VM_PT_EXCL_ACC;
  1083.     Sync_Broadcast(&segPtr->condition);
  1084.  
  1085.     UNLOCK_MONITOR;
  1086.     return(status);
  1087. }
  1088.  
  1089.  
  1090. /*
  1091.  * ----------------------------------------------------------------------------
  1092.  *
  1093.  * VmDecPTUserCount --
  1094.  *
  1095.  *         Decrement the number of users of the page tables for this segment.
  1096.  *    If the count goes to zero then wake up anyone waiting on it.
  1097.  *
  1098.  * Results:
  1099.  *     None.
  1100.  *
  1101.  * Side effects:
  1102.  *     Count of users of page table decremented.
  1103.  *     
  1104.  * ----------------------------------------------------------------------------
  1105.  */
  1106. ENTRY void
  1107. VmDecPTUserCount(segPtr)
  1108.     register    Vm_Segment        *segPtr;
  1109. {
  1110.     LOCK_MONITOR;
  1111.  
  1112.     segPtr->ptUserCount--;
  1113.     if (segPtr->ptUserCount == 0) {
  1114.     Sync_Broadcast(&segPtr->condition);
  1115.     }
  1116.  
  1117.     UNLOCK_MONITOR;
  1118. }
  1119.  
  1120. static void StartExpansion _ARGS_((Vm_Segment *segPtr));
  1121. static void EndExpansion _ARGS_((Vm_Segment *segPtr));
  1122. static void AllocMoreSpace _ARGS_((register Vm_Segment *segPtr, int newNumPages, register VmSpace *spacePtr));
  1123.  
  1124.  
  1125. /*
  1126.  *----------------------------------------------------------------------
  1127.  *
  1128.  * VmAddToSeg --
  1129.  *
  1130.  *    Make all pages between firstPage and lastPage be in the segment's 
  1131.  *    virtual address space.
  1132.  *
  1133.  * Results:
  1134.  *    An error if for some reason the range of virtual pages cannot be
  1135.  *    put into the segment's VAS.  Otherwise SUCCESS is returned.
  1136.  *
  1137.  * Side effects:
  1138.  *    None.
  1139.  *
  1140.  *----------------------------------------------------------------------
  1141.  */
  1142. ReturnStatus
  1143. VmAddToSeg(segPtr, firstPage, lastPage)
  1144.     register Vm_Segment *segPtr;    /* The segment whose VAS is to be
  1145.                      * modified. */
  1146.     int                       firstPage;     /* The lowest page to put into the 
  1147.                      * VAS. */
  1148.     int                       lastPage;     /* The highest page to put into the 
  1149.                      * VAS. */
  1150. {
  1151.     VmSpace    newSpace;
  1152.     VmSpace    oldSpace;
  1153.     int        retValue;
  1154.     int        newNumPages;
  1155.  
  1156.     /*
  1157.      * The only segments that can be expanded are the stack, heap, and
  1158.      * shared segments.
  1159.      */
  1160.     if (segPtr->type == VM_CODE || segPtr->type == VM_SYSTEM) {
  1161.     return(VM_WRONG_SEG_TYPE);
  1162.     }
  1163.  
  1164.     StartExpansion(segPtr);
  1165.  
  1166.     if (segPtr->type == VM_STACK) {
  1167.     newNumPages = mach_LastUserStackPage - firstPage + 1;
  1168.     AllocMoreSpace(segPtr, newNumPages, &newSpace);
  1169.     } else {
  1170.     newNumPages = lastPage - segPtr->offset + 1;
  1171.     AllocMoreSpace(segPtr, newNumPages, &newSpace);
  1172.     }
  1173.  
  1174.     retValue = AddToSeg(segPtr, firstPage, lastPage, newNumPages, 
  1175.             newSpace, &oldSpace);
  1176.     if (oldSpace.spaceToFree && oldSpace.ptPtr != (Vm_PTE *)NIL) {
  1177.     free((Address)oldSpace.ptPtr);
  1178.     }
  1179.     VmMach_SegExpand(segPtr, firstPage, lastPage);
  1180.  
  1181.     EndExpansion(segPtr);
  1182.  
  1183.     return(retValue);
  1184. }
  1185.  
  1186.  
  1187. /*
  1188.  *----------------------------------------------------------------------
  1189.  *
  1190.  * StartExpansion --
  1191.  *
  1192.  *    Grab exclusive access to the page tables.
  1193.  *
  1194.  * Results:
  1195.  *    None.
  1196.  *
  1197.  * Side effects:
  1198.  *    Page table user count incremented and VM_PT_EXCL_ACC flag set.
  1199.  *
  1200.  *----------------------------------------------------------------------
  1201.  */
  1202. ENTRY static void
  1203. StartExpansion(segPtr)
  1204.     Vm_Segment    *segPtr;
  1205. {
  1206.     LOCK_MONITOR;
  1207.  
  1208.     while (segPtr->ptUserCount > 0) {
  1209.     (void)Sync_Wait(&segPtr->condition, FALSE);
  1210.     }
  1211.     segPtr->flags |= VM_PT_EXCL_ACC;
  1212.     segPtr->ptUserCount++;
  1213.  
  1214.     UNLOCK_MONITOR;
  1215. }
  1216.  
  1217.  
  1218.  
  1219. /*
  1220.  *----------------------------------------------------------------------
  1221.  *
  1222.  * EndExpansion --
  1223.  *
  1224.  *    Release the lock on the page tables that prevents expansions and
  1225.  *    deletions from the segment.
  1226.  *
  1227.  * Results:
  1228.  *    None.
  1229.  *
  1230.  * Side effects:
  1231.  *    Page table user count decremented and VM_PT_EXCL_ACC flag cleared.
  1232.  *
  1233.  *----------------------------------------------------------------------
  1234.  */
  1235. ENTRY static void
  1236. EndExpansion(segPtr)
  1237.     Vm_Segment    *segPtr;
  1238. {
  1239.     LOCK_MONITOR;
  1240.  
  1241.     segPtr->flags &= ~VM_PT_EXCL_ACC;
  1242.     segPtr->ptUserCount--;
  1243.     Sync_Broadcast(&segPtr->condition);
  1244.  
  1245.     UNLOCK_MONITOR;
  1246. }
  1247.  
  1248.  
  1249. /*
  1250.  *----------------------------------------------------------------------
  1251.  *
  1252.  * AllocMoreSpace --
  1253.  *
  1254.  *    Allocate more space for the page tables for this segment that is
  1255.  *    growing.  endVirtPage is the highest accessible page if it is
  1256.  *    a heap segment and the lowest accessible page if it is a stack
  1257.  *     segment.
  1258.  *
  1259.  * Results:
  1260.  *    None.
  1261.  *
  1262.  * Side effects:
  1263.  *    The page table might be expanded.
  1264.  *
  1265.  *----------------------------------------------------------------------
  1266.  */
  1267. static void
  1268. AllocMoreSpace(segPtr, newNumPages, spacePtr)
  1269.     register    Vm_Segment    *segPtr;
  1270.     int                newNumPages;
  1271.     register    VmSpace        *spacePtr;
  1272. {
  1273.     /*
  1274.      * Find out the new size of the page table.
  1275.      */
  1276.     spacePtr->ptSize = ((newNumPages - 1)/vmPageTableInc + 1) * vmPageTableInc;
  1277.     /*
  1278.      * Since page tables never get smaller we can see if the page table
  1279.      * is already big enough.
  1280.      */
  1281.     if (spacePtr->ptSize <= segPtr->ptSize) {
  1282.     spacePtr->ptPtr = (Vm_PTE *) NIL;
  1283.     } else {
  1284.     spacePtr->ptPtr = (Vm_PTE *)malloc(sizeof(Vm_PTE) * spacePtr->ptSize);
  1285.     }
  1286. }
  1287.  
  1288.  
  1289. /*
  1290.  *----------------------------------------------------------------------
  1291.  *
  1292.  * AddToSeg --
  1293.  *
  1294.  *    Make all pages between firstPage and lastPage be in the segments 
  1295.  *    virtual address space.
  1296.  *
  1297.  * Results:
  1298.  *    An error if for some reason the range of virtual pages cannot be
  1299.  *    put into the segment's VAS.  Otherwise SUCCESS is returned.
  1300.  *
  1301.  * Side effects:
  1302.  *    None.
  1303.  *
  1304.  *----------------------------------------------------------------------
  1305.  */
  1306. ENTRY static ReturnStatus 
  1307. AddToSeg(segPtr, firstPage, lastPage, newNumPages, newSpace, oldSpacePtr)
  1308.     register    Vm_Segment    *segPtr;    /* The segment to add the
  1309.                          * virtual pages to. */
  1310.     int                firstPage;    /* The lowest page to put
  1311.                          * into the VAS. */
  1312.     int                lastPage;    /* The highest page to put
  1313.                          * into the VAS. */
  1314.     int                newNumPages;    /* The new number of pages
  1315.                          * that will be in the
  1316.                          * segment. */
  1317.     VmSpace            newSpace;    /* Pointer to new page table
  1318.                          * if the segment has to
  1319.                          * be expanded. */
  1320.     VmSpace            *oldSpacePtr;    /* Place to return pointer
  1321.                          * to space to free. */
  1322. {
  1323.     int                copySize;
  1324.     int                byteOffset;
  1325.     register    VmProcLink    *procLinkPtr;
  1326.     register    Vm_Segment    *otherSegPtr;
  1327.  
  1328.     LOCK_MONITOR;
  1329.  
  1330.     *oldSpacePtr = newSpace;
  1331.     oldSpacePtr->spaceToFree = TRUE;
  1332.  
  1333.     copySize = segPtr->ptSize * sizeof(Vm_PTE);
  1334.     if (newNumPages > segPtr->ptSize) {
  1335.     if (segPtr->type == VM_HEAP) {
  1336.         /*
  1337.          * Go through all proc table entries for all processes sharing
  1338.          * this segment and make sure that no stack segment is too large.
  1339.          */
  1340.         LIST_FORALL(segPtr->procList, (List_Links *) procLinkPtr) {
  1341.         otherSegPtr = 
  1342.             procLinkPtr->procPtr->vmPtr->segPtrArray[VM_STACK];
  1343.         if (newSpace.ptSize + segPtr->offset >= otherSegPtr->offset) {
  1344.             UNLOCK_MONITOR;
  1345.             return(VM_SEG_TOO_LARGE);
  1346.         }
  1347.         }
  1348.         /*
  1349.          * This isn't a stack segment so just copy the page table 
  1350.          * into the lower part, and zero the rest.
  1351.          */
  1352.         bcopy((Address) segPtr->ptPtr, (Address) newSpace.ptPtr, copySize);
  1353.         bzero((Address) ((int) (newSpace.ptPtr) + copySize),
  1354.             (newSpace.ptSize - segPtr->ptSize)  * sizeof(Vm_PTE));
  1355.     } else if (segPtr->type == VM_STACK) {
  1356.         /*
  1357.          * Make sure that the heap segment isn't too big.  If it is then 
  1358.          * abort.
  1359.          */
  1360.         otherSegPtr = Proc_GetCurrentProc()->vmPtr->segPtrArray[VM_HEAP];
  1361.         if (otherSegPtr->offset + otherSegPtr->ptSize >= 
  1362.         mach_LastUserStackPage - newSpace.ptSize + 1) {
  1363.         UNLOCK_MONITOR;
  1364.         return(VM_SEG_TOO_LARGE);
  1365.         }
  1366.         /*
  1367.          * In this case the current page table has to be copied to the 
  1368.          * high part of the new page table and the lower part has to be 
  1369.          * zeroed.  Also the offset has to be adjusted to compensate for 
  1370.          * making the page table bigger than requested.
  1371.          */
  1372.         byteOffset = (newSpace.ptSize - segPtr->ptSize) * sizeof(Vm_PTE);
  1373.         bcopy((Address) segPtr->ptPtr,
  1374.             (Address) ((int) (newSpace.ptPtr) + byteOffset), copySize);
  1375.         bzero((Address) newSpace.ptPtr, byteOffset);
  1376.         segPtr->offset -= newSpace.ptSize - segPtr->ptSize;
  1377.     }
  1378.     oldSpacePtr->ptPtr = segPtr->ptPtr;
  1379.     segPtr->ptPtr = newSpace.ptPtr;
  1380.     segPtr->ptSize = newSpace.ptSize;
  1381.     }
  1382.     if (newNumPages > segPtr->numPages) {
  1383.     segPtr->numPages = newNumPages;
  1384.     }
  1385.     /* 
  1386.      * Make all pages between firstPage and lastPage zero-fill-on-demand
  1387.      * members of the segment's virtual address space.
  1388.      */
  1389.     VmValidatePagesInt(segPtr, firstPage, lastPage, TRUE, FALSE);
  1390.  
  1391.     UNLOCK_MONITOR;
  1392.  
  1393.     return(SUCCESS);
  1394. }
  1395.  
  1396. static void IncPTUserCount _ARGS_((register Vm_Segment *segPtr));
  1397. static void CopyInfo _ARGS_((register Vm_Segment *srcSegPtr, register Vm_Segment *destSegPtr, register Vm_PTE **srcPTEPtrPtr, register Vm_PTE **destPTEPtrPtr, Vm_VirtAddr *srcVirtAddrPtr, Vm_VirtAddr *destVirtAddrPtr));
  1398. ENTRY static Boolean CopyPage _ARGS_((Vm_Segment *srcSegPtr,
  1399.     register Vm_PTE *srcPTEPtr, register Vm_PTE *destPTEPtr));
  1400.  
  1401.  
  1402. /*
  1403.  *----------------------------------------------------------------------
  1404.  *
  1405.  * Vm_SegmentDup --
  1406.  *
  1407.  *    Duplicate the given segment and return a pointer to the copy in
  1408.  *    *destSegPtrPtr.  If the segment that is being copied is shared by 
  1409.  *    other processes then the segment could be being modified while it is 
  1410.  *    being copied.  Hence there is no guarantee that the segment will
  1411.  *    be in the same state after it is duplicated as it was when this
  1412.  *    routine was called.
  1413.  *
  1414.  * Results:
  1415.  *    VM_SWAP_ERROR if swap space could not be duplicated or VM_NO_SEGMENTS
  1416.  *    if are out of segments.  Otherwise return SUCCESS.
  1417.  *
  1418.  * Side effects:
  1419.  *    New segment allocated, initialized and copied into.
  1420.  *
  1421.  *----------------------------------------------------------------------
  1422.  */
  1423. ReturnStatus
  1424. Vm_SegmentDup(srcSegPtr, procPtr, destSegPtrPtr)
  1425.     register Vm_Segment *srcSegPtr;    /* Pointer to the segment to be 
  1426.                      * duplicate. */
  1427.     Proc_ControlBlock   *procPtr;     /* Pointer to the process for which the 
  1428.                      * segment is being duplicated. */
  1429.     Vm_Segment        **destSegPtrPtr;/* Place to return pointer to new
  1430.                      * segment. */
  1431. {
  1432.     register    Vm_Segment    *destSegPtr;
  1433.     ReturnStatus        status;
  1434.     register    Vm_PTE        *srcPTEPtr;
  1435.     register    Vm_PTE        *destPTEPtr;
  1436.     Vm_PTE            *tSrcPTEPtr;
  1437.     Vm_PTE            *tDestPTEPtr;
  1438.     Vm_VirtAddr            srcVirtAddr;
  1439.     Vm_VirtAddr            destVirtAddr;
  1440.     int                i;
  1441. #ifndef sequent    
  1442.     Address            srcAddr = (Address) NIL;
  1443.     Address            destAddr = (Address)NIL;
  1444. #endif    
  1445.     Fs_Stream            *newFilePtr;
  1446.  
  1447.     if (srcSegPtr->type == VM_HEAP) {
  1448.     Fsio_StreamCopy(srcSegPtr->filePtr, &newFilePtr);
  1449.     } else {
  1450.     newFilePtr = (Fs_Stream *) NIL;
  1451.     }
  1452.     /*
  1453.      * Prevent the source segment from being expanded.
  1454.      */
  1455.     IncPTUserCount(srcSegPtr);
  1456.  
  1457.     /*
  1458.      * Allocate the segment that we are copying to.
  1459.      */
  1460.     destSegPtr = Vm_SegmentNew(srcSegPtr->type, newFilePtr,
  1461.                    srcSegPtr->fileAddr, srcSegPtr->numPages, 
  1462.                    srcSegPtr->offset, procPtr);
  1463.     if (destSegPtr == (Vm_Segment *) NIL) {
  1464.     VmDecPTUserCount(srcSegPtr);
  1465.     if (srcSegPtr->type == VM_HEAP) {
  1466.         (void)Fs_Close(newFilePtr);
  1467.     }
  1468.     *destSegPtrPtr = (Vm_Segment *) NIL;
  1469.     return(VM_NO_SEGMENTS);
  1470.     }
  1471.     if (vm_CanCOW) {
  1472.     if (VmSegCanCOW(srcSegPtr)) {
  1473.         /*
  1474.          * We are allowing copy-on-write.  Make a copy-on-ref image of the
  1475.          * src segment in the dest segment.
  1476.          */
  1477.         VmSegFork(srcSegPtr, destSegPtr);
  1478.         VmDecPTUserCount(srcSegPtr);
  1479.         *destSegPtrPtr = destSegPtr;
  1480.  
  1481.         VmSegCOWDone(srcSegPtr, FALSE);
  1482.  
  1483.         return(SUCCESS);
  1484.     }
  1485.     }
  1486.  
  1487.     /*
  1488.      * No copy-on-write.  Do a full fledged copy of the source segment to
  1489.      * the dest segment.
  1490.      */
  1491.     CopyInfo(srcSegPtr, destSegPtr, &tSrcPTEPtr, &tDestPTEPtr, &srcVirtAddr,
  1492.          &destVirtAddr);
  1493.  
  1494.     /*
  1495.      * Copy over memory.
  1496.      */
  1497.     for (i = 0, srcPTEPtr = tSrcPTEPtr, destPTEPtr = tDestPTEPtr; 
  1498.      i < destSegPtr->numPages; 
  1499.      i++, VmIncPTEPtr(srcPTEPtr, 1), VmIncPTEPtr(destPTEPtr, 1), 
  1500.         destVirtAddr.page++, srcVirtAddr.page++) {
  1501.     if (CopyPage(srcSegPtr, srcPTEPtr, destPTEPtr)) {
  1502.         *destPTEPtr |= VM_REFERENCED_BIT | VM_MODIFIED_BIT |
  1503.                        VmPageAllocate(&destVirtAddr, VM_CAN_BLOCK);
  1504.         destSegPtr->resPages++;
  1505. #ifndef sequent
  1506.         if (srcAddr == (Address) NIL) {
  1507.         VmMach_FlushPage(&srcVirtAddr, FALSE);
  1508.         srcAddr = VmMapPage(Vm_GetPageFrame(*srcPTEPtr));
  1509.         destAddr = VmMapPage(Vm_GetPageFrame(*destPTEPtr));
  1510.         } else {
  1511.         VmMach_FlushPage(&srcVirtAddr, FALSE);
  1512.         VmRemapPage(srcAddr, Vm_GetPageFrame(*srcPTEPtr));
  1513.         VmRemapPage(destAddr, Vm_GetPageFrame(*destPTEPtr));
  1514.         }
  1515.         bcopy(srcAddr, destAddr, vm_PageSize);
  1516. #else    /* sequent */
  1517.         VmMachCopyPage(Vm_GetPageFrame(*srcPTEPtr),
  1518.                     Vm_GetPageFrame(*destPTEPtr));
  1519. #endif    /* sequent */
  1520.         VmUnlockPage(Vm_GetPageFrame(*srcPTEPtr));
  1521.         VmUnlockPage(Vm_GetPageFrame(*destPTEPtr));
  1522.     }
  1523.     }
  1524. #ifndef sequent    
  1525.     /*
  1526.      * Unmap any mapped pages.
  1527.      */
  1528.     if (srcAddr != (Address) NIL) {
  1529.         VmUnmapPage(srcAddr);
  1530.         VmUnmapPage(destAddr);
  1531.     }
  1532. #endif
  1533.     /*
  1534.      * Copy over swap space resources.
  1535.      */
  1536.     status = VmCopySwapSpace(srcSegPtr, destSegPtr);
  1537.     VmDecPTUserCount(srcSegPtr);
  1538.  
  1539.     /*
  1540.      * If couldn't copy the swap space over then return an error.
  1541.      */
  1542.     if (status != SUCCESS) {
  1543.     Vm_SegmentDelete(destSegPtr, procPtr);
  1544.     return(VM_SWAP_ERROR);
  1545.     }
  1546.  
  1547.     *destSegPtrPtr = destSegPtr;
  1548.  
  1549.     return(SUCCESS);
  1550. }
  1551.  
  1552.  
  1553. /*
  1554.  * ----------------------------------------------------------------------------
  1555.  *
  1556.  * IncPTUserCount --
  1557.  *
  1558.  *         Increment the count of users of the page tables for the given segment.
  1559.  *
  1560.  * Results:
  1561.  *     None.
  1562.  *
  1563.  * Side effects:
  1564.  *     Count of users of page table incremented.
  1565.  *     
  1566.  * ----------------------------------------------------------------------------
  1567.  */
  1568. ENTRY static void
  1569. IncPTUserCount(segPtr)
  1570.     register    Vm_Segment    *segPtr;
  1571. {
  1572.     LOCK_MONITOR;
  1573.  
  1574.     while (segPtr->flags & VM_PT_EXCL_ACC) {
  1575.     (void)Sync_Wait(&segPtr->condition, FALSE);
  1576.     }
  1577.     segPtr->ptUserCount++;
  1578.  
  1579.     UNLOCK_MONITOR;
  1580. }
  1581.  
  1582. /*
  1583.  * ----------------------------------------------------------------------------
  1584.  *
  1585.  * The following routines, VmSegCanCOW, VmSegCantCOW and VmSegCOWDone,
  1586.  * synchronize the marking of a segment as non-copy-on-writeable (i.e. it
  1587.  * has to be copied at fork time). The routines that wire pages into a
  1588.  * user's address space can't allow pages that they have wired down to all
  1589.  * of a sudden become copy-on-write because this can cause page faults
  1590.  * at bad times (e.g. with interrupts disabled).  Thus before they wire
  1591.  * pages down they make sure that the segment that the pages reside in
  1592.  * cannot be made copy-on-write.  They do this by calling the routine
  1593.  * VmSegCantCOW.  The routine above (Vm_SegmentDup) wants to decide if it
  1594.  * should duplicate the segment with COW or with copy-on-fork.  It decides
  1595.  * what to do by calling the routine VmSegCanCOW which will return TRUE
  1596.  * if the segment can be copied copy-on-write and will prevent the routine
  1597.  * VmSegCantCOW from doing its thing.  Once a segment has been successfully
  1598.  * duplicated with COW then the routine VmSegCOWDone is called which allows
  1599.  * VmSegCantCOW to proceed.
  1600.  */
  1601.  
  1602. /*
  1603.  * ----------------------------------------------------------------------------
  1604.  *
  1605.  * VmSegCanCOW --
  1606.  *
  1607.  *         Return TRUE if can fork this segment copy-on-write.  If the 
  1608.  *    VM_SEG_COW_IN_PROGRESS flag is set then wait until its cleared
  1609.  *    before making the decision about whether this segment can
  1610.  *    be forked copy-on-write. 
  1611.  *
  1612.  * Results:
  1613.  *    TRUE if can fork this segment copy-on-write.
  1614.  *
  1615.  * Side effects:
  1616.  *    VM_SEG_COW_IN_PROGRESS flag set if the can be made copy-on-write.
  1617.  *     
  1618.  * ----------------------------------------------------------------------------
  1619.  */
  1620. ENTRY Boolean
  1621. VmSegCanCOW(segPtr)
  1622.     Vm_Segment    *segPtr;
  1623. {
  1624.     Boolean    retVal;
  1625.  
  1626.     LOCK_MONITOR;
  1627.  
  1628.     while (segPtr->flags & VM_SEG_COW_IN_PROGRESS) {
  1629.     (void)Sync_Wait(&segPtr->condition, FALSE);
  1630.     }
  1631.     if (segPtr->flags & VM_SEG_CANT_COW) {
  1632.     retVal = FALSE;
  1633.     } else {
  1634.     retVal = TRUE;
  1635.     segPtr->flags |= VM_SEG_COW_IN_PROGRESS;
  1636.     }
  1637.  
  1638.     UNLOCK_MONITOR;
  1639.  
  1640.     return(retVal);
  1641. }
  1642.  
  1643.  
  1644. /*
  1645.  * ----------------------------------------------------------------------------
  1646.  *
  1647.  * VmSegCOWDone --
  1648.  *
  1649.  *         A copy-on-fork operation has completed.
  1650.  *
  1651.  * Results:
  1652.  *    None.
  1653.  *
  1654.  * Side effects:
  1655.  *    VM_SEG_COW_IN_PROGRESS flag cleared.
  1656.  *     
  1657.  * ----------------------------------------------------------------------------
  1658.  */
  1659. ENTRY void
  1660. VmSegCOWDone(segPtr, cantCOW)
  1661.     Vm_Segment    *segPtr;
  1662.     Boolean    cantCOW;
  1663. {
  1664.     LOCK_MONITOR;
  1665.  
  1666.     if (cantCOW) {
  1667.     segPtr->flags |= VM_SEG_CANT_COW;
  1668.     }
  1669.     segPtr->flags &= ~VM_SEG_COW_IN_PROGRESS;
  1670.     Sync_Broadcast(&segPtr->condition);
  1671.  
  1672.     UNLOCK_MONITOR;
  1673. }
  1674.  
  1675.  
  1676. /*
  1677.  *----------------------------------------------------------------------
  1678.  *
  1679.  * CopyInfo --
  1680.  *
  1681.  *    Copy over pertinent information in the source including page
  1682.  *    tables to the destination segment.
  1683.  *
  1684.  * Results:
  1685.  *    None.
  1686.  *
  1687.  * Side effects:
  1688.  *    Page table and virtual address pointers set for source and destination
  1689.  *    segments.
  1690.  *
  1691.  *----------------------------------------------------------------------
  1692.  */
  1693. ENTRY static void
  1694. CopyInfo(srcSegPtr, destSegPtr, srcPTEPtrPtr, destPTEPtrPtr, 
  1695.      srcVirtAddrPtr, destVirtAddrPtr)
  1696.     register    Vm_Segment    *srcSegPtr;
  1697.     register    Vm_Segment    *destSegPtr;
  1698.     register    Vm_PTE        **srcPTEPtrPtr;
  1699.     register    Vm_PTE        **destPTEPtrPtr;
  1700.     Vm_VirtAddr            *srcVirtAddrPtr;
  1701.     Vm_VirtAddr            *destVirtAddrPtr;
  1702. {
  1703.     LOCK_MONITOR;
  1704.  
  1705.     if (srcSegPtr->type == VM_HEAP) {
  1706.     *srcPTEPtrPtr = srcSegPtr->ptPtr;
  1707.     *destPTEPtrPtr = destSegPtr->ptPtr;
  1708.     destVirtAddrPtr->page = srcSegPtr->offset;
  1709.     } else {
  1710.     destVirtAddrPtr->page = mach_LastUserStackPage - 
  1711.                         srcSegPtr->numPages + 1;
  1712.     *srcPTEPtrPtr = VmGetPTEPtr(srcSegPtr, destVirtAddrPtr->page);
  1713.     *destPTEPtrPtr = VmGetPTEPtr(destSegPtr, destVirtAddrPtr->page);
  1714.     }
  1715.     destVirtAddrPtr->segPtr = destSegPtr;
  1716.     srcVirtAddrPtr->segPtr = srcSegPtr;
  1717.     srcVirtAddrPtr->page = destVirtAddrPtr->page;
  1718.     srcVirtAddrPtr->sharedPtr = (Vm_SegProcList *)NIL;
  1719.     destVirtAddrPtr->sharedPtr = (Vm_SegProcList *)NIL;
  1720.  
  1721.     UNLOCK_MONITOR;
  1722. }
  1723.  
  1724.  
  1725. /*
  1726.  *----------------------------------------------------------------------
  1727.  *
  1728.  * CopyPage --
  1729.  *
  1730.  *    Determine if the page in the source segment needs to be duplicated.
  1731.  *    If the page is to be duplicated then return the source page frame
  1732.  *    locked and return TRUE.  Otherwise return FALSE.
  1733.  *
  1734.  * Results:
  1735.  *    TRUE if page needs to be duplicated, FALSE if not.
  1736.  *
  1737.  * Side effects:
  1738.  *    Source page frame may be locked.
  1739.  *
  1740.  *----------------------------------------------------------------------
  1741.  */
  1742. ENTRY static Boolean
  1743. CopyPage(srcSegPtr, srcPTEPtr, destPTEPtr)
  1744.     Vm_Segment            *srcSegPtr;
  1745.     register    Vm_PTE        *srcPTEPtr;
  1746.     register    Vm_PTE        *destPTEPtr;
  1747. {
  1748.     Boolean    residentPage;
  1749.  
  1750.     LOCK_MONITOR;
  1751.  
  1752.     while (*srcPTEPtr & VM_IN_PROGRESS_BIT) {
  1753.     (void)Sync_Wait(&srcSegPtr->condition, FALSE);
  1754.     }
  1755.     residentPage = *srcPTEPtr & VM_PHYS_RES_BIT;
  1756.     *destPTEPtr = *srcPTEPtr;
  1757.     if (residentPage) {
  1758.     /*
  1759.      * Copy over all resident pages.  Can reload swapped pages but its a 
  1760.      * lot cheaper to do a memory-to-memory copy than send an RPC to the
  1761.      * server to copy the page on swap space.  
  1762.      */
  1763.     VmLockPageInt(Vm_GetPageFrame(*srcPTEPtr));
  1764.     *destPTEPtr &= ~(VM_ON_SWAP_BIT | VM_PAGE_FRAME_FIELD);
  1765.     } else {
  1766.     *destPTEPtr &= ~VM_PAGE_FRAME_FIELD;
  1767.     /* 
  1768.      * This page is on the swap file but not in memory so we are
  1769.      * going to have to copy over the swap space for this page.
  1770.      * Use the in-progress bit to mark this fact.
  1771.      */
  1772.     if (*destPTEPtr & VM_ON_SWAP_BIT) {
  1773.         *destPTEPtr |= VM_IN_PROGRESS_BIT;
  1774.     }
  1775.     }
  1776.  
  1777.     UNLOCK_MONITOR;
  1778.  
  1779.     return(residentPage);
  1780. }
  1781.  
  1782.  
  1783. /*
  1784.  *----------------------------------------------------------------------
  1785.  *
  1786.  * SegmentIncRef --
  1787.  *
  1788.  *    Increment the reference count for the given segment and put it into
  1789.  *    the list of processes sharing this segment.
  1790.  *
  1791.  * Results:
  1792.  *    None.
  1793.  *
  1794.  * Side effects:
  1795.  *    The given segment in the segment table is modified.
  1796.  *
  1797.  *----------------------------------------------------------------------
  1798.  */
  1799. ENTRY static void
  1800. SegmentIncRef(segPtr, procLinkPtr) 
  1801.     register    Vm_Segment    *segPtr;
  1802.     register    VmProcLink    *procLinkPtr;
  1803. {
  1804.     LOCK_MONITOR;
  1805.  
  1806.     segPtr->refCount++;
  1807.  
  1808.     /*
  1809.      * Put the process into the list of processes sharing this segment.
  1810.      */
  1811.     List_Insert((List_Links *) procLinkPtr, LIST_ATFRONT(segPtr->procList));
  1812.  
  1813.     UNLOCK_MONITOR;
  1814. }
  1815.  
  1816.  
  1817. /*
  1818.  *----------------------------------------------------------------------
  1819.  *
  1820.  * Vm_SegmentIncRef --
  1821.  *
  1822.  *    Increment the reference count for the given segment and put it into
  1823.  *    the list of processes sharing this segment.
  1824.  *
  1825.  * Results:
  1826.  *    None.
  1827.  *
  1828.  * Side effects:
  1829.  *    The given segment in the segment table is modified.
  1830.  *
  1831.  *----------------------------------------------------------------------
  1832.  */
  1833. void
  1834. Vm_SegmentIncRef(segPtr, procPtr) 
  1835.     Vm_Segment        *segPtr;
  1836.     Proc_ControlBlock    *procPtr;
  1837. {
  1838.     register    VmProcLink    *procLinkPtr;
  1839.  
  1840.     procLinkPtr = (VmProcLink *) malloc(sizeof(VmProcLink));
  1841.     procLinkPtr->procPtr = procPtr;
  1842.  
  1843.     SegmentIncRef(segPtr, procLinkPtr);
  1844. }
  1845.  
  1846.  
  1847. /*
  1848.  *----------------------------------------------------------------------
  1849.  *
  1850.  * Vm_GetSegInfo --
  1851.  *
  1852.  *
  1853.  *    This routine takes in a pointer to a proc table entry and returns
  1854.  *    the segment table information for the segments that it uses.
  1855.  *    If the proc table entry corresponds to a migrated process,
  1856.  *     contact its current host.
  1857.  *
  1858.  * Results:
  1859.  *    SUCCESS if could get the information, SYS_ARG_NOACCESS if the
  1860.  *    the pointer to the segment table entries passed in are bad amd
  1861.  *    SYS_INVALID_ARG if one of the segment pointers in the proc table
  1862.  *    are bad.  Or, the result from the RPC to get the migrated process's
  1863.  *    info.
  1864.  *
  1865.  * Side effects:
  1866.  *    None.
  1867.  *
  1868.  *----------------------------------------------------------------------
  1869.  */
  1870.  
  1871. ReturnStatus
  1872. Vm_GetSegInfo(infoPtr, segID, infoSize, segBufPtr)
  1873.     Proc_PCBInfo    *infoPtr;    /* User's copy of PCB.  Contains
  1874.                      * pointers to segment structures.
  1875.                      * USER_NIL => Want to use a 
  1876.                      *     specific segment number. */
  1877.     Vm_SegmentID    segID;        /* Segment number of get info for.  
  1878.                      * Ignored unless previous argument
  1879.                      * is USER_NIL. */
  1880.     int            infoSize;    /* Size of segment info structures */
  1881.     Address        segBufPtr;    /* Where to store segment information.*/
  1882. {
  1883.     Proc_PCBInfo    pcbInfo;
  1884.     Vm_Segment        *minSegAddr, *maxSegAddr, *segPtr;
  1885.     int            i;
  1886.     int            segNum;
  1887.     int            bytesToCopy;
  1888.     Vm_SegmentInfo    segmentInfo;
  1889.     int            host;
  1890.     Proc_ControlBlock    *procPtr;
  1891.     ReturnStatus     status;
  1892.  
  1893.     segNum = (int) segID;
  1894.     bytesToCopy = min(sizeof(Vm_SegmentInfo), infoSize);
  1895.     minSegAddr = segmentTable;
  1896.     maxSegAddr = &(segmentTable[vmNumSegments - 1]);
  1897.     if (infoPtr != (Proc_PCBInfo *)USER_NIL) {
  1898.     if (Vm_CopyIn(sizeof(pcbInfo), (Address) infoPtr,
  1899.               (Address) &pcbInfo) != SUCCESS) {
  1900.         return(SYS_ARG_NOACCESS);
  1901.     }
  1902.     /*
  1903.      * Follow remote processes.  Use the peerHostID as a hint.
  1904.      */
  1905.     host = 0;
  1906.     if (pcbInfo.peerHostID != (int) NIL) {
  1907.         procPtr = Proc_LockPID(pcbInfo.processID);
  1908.         if (procPtr != (Proc_ControlBlock *) NIL) {
  1909.         if (procPtr->state == PROC_MIGRATED) {
  1910.             host = procPtr->peerHostID;
  1911.         }
  1912.         Proc_Unlock(procPtr);
  1913.         }
  1914.     }
  1915.     for (i = VM_CODE; i <= VM_STACK; i++, segBufPtr += infoSize) {
  1916.         if (pcbInfo.genFlags & PROC_KERNEL) {
  1917.         segPtr = vm_SysSegPtr;
  1918.         FillSegmentInfo(segPtr, &segmentInfo);
  1919.         } else {
  1920.         segNum = pcbInfo.vmSegments[i];
  1921.         if (segNum < 0 || segNum >= vmNumSegments) {
  1922.             return(SYS_INVALID_ARG);
  1923.         }
  1924.         if (host) {
  1925.             status = Proc_GetRemoteSegInfo(host, segNum, &segmentInfo);
  1926.             if (status != SUCCESS) {
  1927.             return(status);
  1928.             }
  1929.         } else {
  1930.             segPtr = &segmentTable[segNum];
  1931.             if (segPtr < minSegAddr || segPtr > maxSegAddr) {
  1932.             return(SYS_INVALID_ARG);
  1933.             }
  1934.             FillSegmentInfo(segPtr, &segmentInfo);
  1935.         }
  1936.         }
  1937.         if (Vm_CopyOut(bytesToCopy, (Address) &segmentInfo, 
  1938.                segBufPtr) != SUCCESS) { 
  1939.         return(SYS_ARG_NOACCESS);
  1940.         }
  1941.     }
  1942.     } else if (segNum < 0 || segNum >= vmNumSegments) {
  1943.     return(SYS_INVALID_ARG);
  1944.     } else {
  1945.     segPtr = &segmentTable[segNum];
  1946.     if (segPtr < minSegAddr || segPtr > maxSegAddr) {
  1947.         return(SYS_INVALID_ARG);
  1948.     }
  1949.     FillSegmentInfo(segPtr, &segmentInfo);
  1950.     if (Vm_CopyOut(bytesToCopy, (Address) &segmentInfo, 
  1951.                segBufPtr) != SUCCESS) { 
  1952.         return(SYS_ARG_NOACCESS);
  1953.     }
  1954.     }
  1955.  
  1956.     return(SUCCESS);
  1957. }
  1958.  
  1959. /*
  1960.  *----------------------------------------------------------------------
  1961.  *
  1962.  * FillSegmentInfo --
  1963.  *
  1964.  *    Converts the contents of a Vm_Segment to a Vm_SegmentInfo.
  1965.  *    This allows the kernel definition of Vm_Segment to change without
  1966.  *    affecting user programs.
  1967.  *
  1968.  * Results:
  1969.  *    None.
  1970.  *
  1971.  * Side effects:
  1972.  *    None.
  1973.  *
  1974.  *----------------------------------------------------------------------
  1975.  */
  1976.  
  1977. static void
  1978. FillSegmentInfo(segPtr, infoPtr)
  1979.     Vm_Segment        *segPtr;    /* Segment to convert */
  1980.     Vm_SegmentInfo    *infoPtr;    /* Conversion result */
  1981. {
  1982.     infoPtr->segNum = segPtr->segNum;
  1983.     infoPtr->refCount = segPtr->refCount;
  1984.     infoPtr->type = segPtr->type;
  1985.     if (infoPtr->type == VM_CODE) {
  1986.     (void)strncpy(infoPtr->objFileName, segPtr->objFileName,
  1987.             VM_OBJ_FILE_NAME_LENGTH);
  1988.     infoPtr->objFileName[VM_OBJ_FILE_NAME_LENGTH -1] = '\0';
  1989.     } else {
  1990.     infoPtr->objFileName[0] = '\0';
  1991.     }
  1992.     infoPtr->numPages = segPtr->numPages;
  1993.     infoPtr->ptSize = segPtr->ptSize;
  1994.     infoPtr->resPages = segPtr->resPages;
  1995.     infoPtr->flags = segPtr->flags;
  1996.     infoPtr->ptUserCount = segPtr->ptUserCount;
  1997.     infoPtr->numCOWPages = segPtr->numCOWPages;
  1998.     infoPtr->numCORPages = segPtr->numCORPages;
  1999.     infoPtr->minAddr = segPtr->minAddr;
  2000.     infoPtr->maxAddr = segPtr->maxAddr;
  2001.     return;
  2002. }
  2003.  
  2004.  
  2005. /*
  2006.  *----------------------------------------------------------------------
  2007.  *
  2008.  * VmGetSegPtr --
  2009.  *
  2010.  *    Return a pointer to the given segment.
  2011.  *
  2012.  * Results:
  2013.  *    Pointer to given segment.
  2014.  *
  2015.  * Side effects:
  2016.  *    None.
  2017.  *
  2018.  *----------------------------------------------------------------------
  2019.  */
  2020. Vm_Segment *
  2021. VmGetSegPtr(segNum)
  2022.     int    segNum;
  2023. {
  2024.     return(&segmentTable[segNum]);
  2025. }
  2026.  
  2027.  
  2028. /*
  2029.  *----------------------------------------------------------------------
  2030.  *
  2031.  * Vm_EncapSegInfo --
  2032.  *
  2033.  *    Encapsulate information for a particular segment.  This is used
  2034.  *     to send info to other hosts (for ps, e.g.).
  2035.  *
  2036.  * Results:
  2037.  *    SUCCESS, or invalid arg if the segment doesn't exist.
  2038.  *
  2039.  * Side effects:
  2040.  *    None.
  2041.  *
  2042.  *----------------------------------------------------------------------
  2043.  */
  2044. ReturnStatus
  2045. Vm_EncapSegInfo(segNum, infoPtr)
  2046.     int    segNum;            /* Number of the segment. */
  2047.     Vm_SegmentInfo *infoPtr;    /* Pointer to encapsulated data. */
  2048. {
  2049.     Vm_Segment *segPtr;
  2050.     segPtr = &segmentTable[segNum];
  2051.     if (segPtr < segmentTable ||
  2052.     segPtr > &(segmentTable[vmNumSegments - 1])) {
  2053.     return(GEN_INVALID_ARG);
  2054.     }
  2055.     FillSegmentInfo(segPtr, infoPtr);
  2056.     return(SUCCESS);
  2057. }
  2058.  
  2059.